package com.jrx.anytxn.common.uitl;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import org.springframework.util.StopWatch;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * AnyTxn应用部署
 */
public class TxnAppDeploy {

    //  环境账号和密码
    public static Map<String, String> apMap = new HashMap<>();

    static {
        apMap.put("branch", "ccs&Xib@88888888");
        apMap.put("trunk", "ccs&Abcd@1234");
    }

    //  环境账号和密码
    public static Map<String, List<String>> hostMap = new HashMap<>();

    static {
        // branch
        hostMap.put("branch-transaction-api&customer-api", Arrays.asList("10.71.141.174", "10.71.133.251"));
        hostMap.put("branch-param-api&reporting-api", Arrays.asList("10.71.141.70", "10.71.142.83"));
        hostMap.put("branch-accounting-api&investor-api", Arrays.asList("10.71.142.21", "10.71.141.91"));
        hostMap.put("branch-timer", Arrays.asList("10.71.135.145", "10.71.129.223"));
        hostMap.put("branch-batch", Arrays.asList("10.71.134.113", "10.71.130.248"));

        // trunk
        hostMap.put("trunk-transaction-api&customer-api", Arrays.asList("10.71.140.79", "10.71.140.90", "10.71.142.135"));
        hostMap.put("trunk-param-api&reporting-api", Arrays.asList("10.71.139.72", "10.71.143.8"));
        hostMap.put("trunk-accounting-api&investor-api", Arrays.asList("10.71.139.146", "10.71.137.73"));
        hostMap.put("trunk-timer", Arrays.asList("10.71.137.71", "10.71.138.254", "10.71.137.37", "10.71.139.60"));
        hostMap.put("trunk-batch", Arrays.asList("10.71.142.163", "10.71.143.220", "10.71.142.208"));
    }

    /**
     * 获取文件规则
     */
    public static List<String> typeRules = Arrays.asList(
            "api.tar.gz"
            , "batch.jar"
            , "timer.jar"
    );
    /**
     * 固定前缀
     */
    public static String prefixPath = "anytxn-cf-";

    /**
     * 本地文件路径
     */
    public static String localFilePath = System.getProperty("user.dir");
    ;
    /**
     * 固定前缀
     */
    public static String evn = "branch";
    //public static String evn = "trunk";

    public static List<String> appRules = new ArrayList<>();

    static {
        //appRules.add("accounting-api");
        //appRules.add("investor-api");
        //appRules.add("param-api");
        //appRules.add("reporting-api");
        appRules.add("transaction-api");
        appRules.add("customer-api");
        //appRules.add("transaction-timer");
        //appRules.add("accounting-batch");
        //appRules.add("cust-atom-batch");
        //appRules.add("param-batch");
        //appRules.add("reporting-batch");
        appRules.add("transaction-batch");
        //appRules.add("transaction-param-batch");
    }


    //public static void main(String[] args) {
    //    Properties properties = System.getProperties();
    //    String property = System.getProperty("user.dir");
    //    System.out.println(properties);
    //}

    public static void main(String[] args) {

        StopWatch stopWatch = new StopWatch("应用上传部署");
        stopWatch.start();
        File file = new File(localFilePath);
        if (!file.exists()) {
            System.out.println("文件目录不存在");
            return;
        }
        String ap = apMap.get(evn);
        String[] split = ap.split("&");
        String remoteUsername = split[0];
        String remotePassword = split[1];

        List<String> fileNames = getFileNames(file, appRules);

        for (String appRule : appRules) {
            for (Map.Entry<String, List<String>> entry : hostMap.entrySet()) {
                String key = entry.getKey();
                String app = appRule;
                boolean batch = appRule.contains("batch");
                boolean timer = appRule.contains("timer");
                if (batch) {
                    app = "batch";
                }
                if (timer) {
                    app = "timer";
                }
                boolean contains = key.contains(evn) && key.contains(app);
                if (contains) {
                    List<String> hosts = entry.getValue();
                    for (String remoteHost : hosts) {
                        String remoteFolderPath = "/data/apps/anytxn/";
                        if (key.endsWith("api")) {
                            remoteFolderPath = remoteFolderPath + prefixPath + appRule + "/";
                        } else if (key.endsWith("batch")) {
                            remoteFolderPath = "/data/apps/batch_schedule/jarhome/";
                        } else if (key.endsWith("timer")) {
                            remoteFolderPath = "/data/apps/anytxn/anytxn-cf-transaction-timer/";
                            remoteFolderPath = "10.71.129.223,10.71.137.71,10.71.137.37".contains(remoteHost) ? remoteFolderPath + evn + "1011" : remoteFolderPath;
                            remoteFolderPath = "10.71.135.145,10.71.138.254,10.71.139.60".contains(remoteHost) ? remoteFolderPath + evn + "1012" : remoteFolderPath;
                        }
                        String filePath = fileNames.stream().filter(f -> f.contains(appRule)).findFirst().get();
                        System.out.println("source:" + filePath);
                        boolean change = false;
                        String newRemotePassword = "Xib@1357924680.";
                        if (Arrays.asList("10.71.134.113","10.71.129.223").contains(remoteHost)) {
                            change = true;
                        }
                        System.out.println("target:" + remoteUsername + "@" + remoteHost + remoteFolderPath + " -p:" + (change ? newRemotePassword : remotePassword));
                        uploadFileToLinux(filePath, remoteUsername, (change ? newRemotePassword : remotePassword), remoteHost, remoteFolderPath, appRule);
                    }

                }

            }
        }
        stopWatch.stop();
        System.out.println("总耗时：" + stopWatch.getTotalTimeSeconds() + "秒");

    }

    /**
     * 上传到服务器
     *
     * @param filePath         本地文件路径
     * @param remoteUsername   登录服务器用户名
     * @param remotePassword   登录服务器用密码
     * @param remoteHost       登录服务器IP
     * @param remoteFolderPath 服务器路径
     * @param appRule          app规则
     */
    private static void uploadFileToLinux(String filePath, String remoteUsername, String remotePassword, String remoteHost, String remoteFolderPath, String appRule) {
        JSch jsch = new JSch();
        Session session = null;
        ChannelSftp channelSftp = null;
        ChannelExec channelExec = null;
        try {
            session = jsch.getSession(remoteUsername, remoteHost, 22);
            session.setPassword(remotePassword);
            session.setConfig("StrictHostKeyChecking", "no");
            session.connect();

            channelSftp = (ChannelSftp) session.openChannel("sftp");
            channelSftp.connect();

            channelSftp.put(filePath, remoteFolderPath);

            System.out.println("File uploaded successfully.");
            Channel channel = session.openChannel("exec");
            channelExec = (ChannelExec) channel;
            String deleteCmd = "";
            String restartCmd = "";
            if (filePath.endsWith("gz")) {
                String app = appRule.replaceAll("-api", "");
                deleteCmd = "sh " + remoteFolderPath + "bin/" + "delete-" + app + "-tar.sh";
                // anytxn-cf-param-api.sh
                restartCmd = "sh " + remoteFolderPath + "bin/" + prefixPath + appRule + ".sh restart " + evn;
                channelExec.setCommand(deleteCmd + "\n" + restartCmd);

            } else if (filePath.endsWith("timer.jar")) {
                deleteCmd = "sh " + remoteFolderPath + "/bin/" + "delete-" + appRule + "-jar.sh";
                // anytxn-cf-transaction-timer.sh
                String evnParam = remoteFolderPath.substring(remoteFolderPath.lastIndexOf("/") + 1);
                restartCmd = "sh " + remoteFolderPath + "/bin/" + prefixPath + appRule + ".sh restart " + evnParam;
                channelExec.setCommand(deleteCmd + "\n" + restartCmd);
            } else {
                channelExec.setCommand("");
            }
            System.out.println("执行删除命令：" + deleteCmd);
            System.out.println("执行启动命令：" + restartCmd);
            InputStream in = channel.getInputStream();
            channel.connect();

            StringBuilder sb = new StringBuilder();
            int c;
            while ((c = in.read()) != -1) {
                sb.append((char) c);
            }
            System.out.println("输出的结果是：" + sb.toString());


        } catch (JSchException | SftpException | IOException e) {
            e.printStackTrace();
        } finally {
            if (channelSftp != null && channelSftp.isConnected()) {
                channelSftp.disconnect();
            }
            if (channelExec != null && channelExec.isConnected()) {
                channelExec.disconnect();
            }
            if (session != null && session.isConnected()) {
                session.disconnect();
            }
        }
    }

    /**
     * 获取文件名称
     *
     * @param file
     * @param appRules
     * @return
     */
    private static List<String> getFileNames(File file, List<String> appRules) {
        List<String> list = new ArrayList<>();
        File[] files = file.listFiles();
        assert files != null;
        for (File f : files) {
            if (f.isDirectory()) {
                List<String> fileNames = getFileNames(f, appRules);
                list.addAll(fileNames);
            } else {
                String absolutePath = f.getAbsolutePath();
                boolean typeRule = typeRules.stream().anyMatch(absolutePath::endsWith);
                boolean appRule = appRules.stream().anyMatch(absolutePath::contains);
                if (typeRule && appRule) {
                    list.add(absolutePath);
                }
            }
        }
        return list;
    }
}